home *** CD-ROM | disk | FTP | other *** search
/ Aminet 7 / Aminet 7 - August 1995.iso / Aminet / comm / tcp / AmigaTCP.lha / AmigaTCP / src / tcpuser.c < prev    next >
C/C++ Source or Header  |  1989-06-24  |  6KB  |  281 lines

  1. /* User calls to TCP */
  2. #include "machdep.h"
  3. #include "timer.h"
  4. #include "mbuf.h"
  5. #include "netuser.h"
  6. #include "internet.h"
  7. #include "ip.h"
  8. #include "tcp.h"
  9.  
  10. int16 tcp_window = DEF_WND;
  11.  
  12. struct tcb *
  13. open_tcp(lsocket,fsocket,active,window,r_upcall,t_upcall,s_upcall,tos,user)
  14. struct socket *lsocket;    /* Local socket */
  15. struct socket *fsocket;    /* Remote socket */
  16. int active;        /* Active/passive */
  17. int16 window;        /* Receive window (and send buffer) sizes */
  18. void (*r_upcall)();    /* Function to call when data arrives */
  19. void (*t_upcall)();    /* Function to call when ok to send more data */
  20. void (*s_upcall)();    /* Function to call when connection state changes */
  21. char tos;
  22. int *user;        /* User linkage area */
  23. {
  24.     struct connection conn;
  25.     register struct tcb *tcb;
  26.     void send_syn();
  27.  
  28.     if(lsocket == NULLSOCK){
  29.         net_error = INVALID;
  30.         return NULLTCB;
  31.     }
  32.     conn.local.address = lsocket->address;
  33.     conn.local.port = lsocket->port;
  34.     if(fsocket != NULLSOCK){
  35.         conn.remote.address = fsocket->address;
  36.         conn.remote.port = fsocket->port;
  37.     } else {
  38.         conn.remote.address = 0;
  39.         conn.remote.port = 0;
  40.     }
  41.     if((tcb = lookup_tcb(&conn)) == NULLTCB){
  42.         if((tcb = create_tcb(&conn)) == NULLTCB){
  43.             net_error = NO_SPACE;
  44.             return NULLTCB;
  45.         }
  46.     } else if(tcb->state != LISTEN){
  47.         net_error = CON_EXISTS;
  48.         return NULLTCB;
  49.     }
  50.     tcb->user = user;
  51.     if(window != 0)
  52.         tcb->window = tcb->rcv.wnd = window;
  53.     else
  54.         tcb->window = tcb->rcv.wnd = tcp_window;
  55.     tcb->r_upcall = r_upcall;
  56.     tcb->t_upcall = t_upcall;
  57.     tcb->s_upcall = s_upcall;
  58.     tcb->tos = tos;
  59.     if(!active){
  60.         setstate(tcb,LISTEN);
  61.         return tcb;
  62.     }
  63.     /* Send SYN, go into SYN_SENT state */
  64.     send_syn(tcb);
  65.     setstate(tcb,SYN_SENT);
  66.     tcp_output(tcb);
  67.     tcp_stat.conout++;
  68.     return tcb;
  69. }
  70. /* User send routine */
  71. int
  72. send_tcp(tcb,bp)
  73. register struct tcb *tcb;
  74. struct mbuf *bp;
  75. {
  76.     int16 cnt;
  77.  
  78.     if(tcb == NULLTCB || bp == NULLBUF){
  79.         free_p(bp);
  80.         net_error = INVALID;
  81.         return -1;
  82.     }
  83.     cnt = len_mbuf(bp);
  84. #ifdef    TIGHT
  85.     /* If this would overfill our send queue, reject it entirely */
  86.     if(tcb->sndcnt + cnt > tcb->window){
  87.         free_p(bp);
  88.         net_error = WOULDBLK;
  89.         return -1;
  90.     }
  91. #endif
  92.     switch(tcb->state){
  93.     case CLOSED:
  94.         free_p(bp);
  95.         net_error = NO_CONN;
  96.         return -1;
  97.     case LISTEN:    /* Change state from passive to active */
  98.         send_syn(tcb);
  99.         setstate(tcb,SYN_SENT);    /* Note fall-thru */
  100.     case SYN_SENT:
  101.     case SYN_RECEIVED:
  102.     case ESTABLISHED:
  103.     case CLOSE_WAIT:
  104.         append(&tcb->sndq,bp);
  105.         tcb->sndcnt += cnt;
  106.         tcp_output(tcb);
  107.         break;
  108.     case FINWAIT1:
  109.     case FINWAIT2:
  110.     case CLOSING:
  111.     case LAST_ACK:
  112.     case TIME_WAIT:
  113.         free_p(bp);
  114.         net_error = CON_CLOS;
  115.         return -1;
  116.     }
  117.     return cnt;
  118. }
  119. /* User receive routine */
  120. int
  121. recv_tcp(tcb,bp,cnt)
  122. register struct tcb *tcb;
  123. struct mbuf **bp;
  124. int16 cnt;
  125. {
  126.     if(tcb == NULLTCB || bp == (struct mbuf **)NULL){
  127.         net_error = INVALID;
  128.         return -1;
  129.     }
  130.     /* cnt == 0 means "I want it all" */
  131.     if(cnt == 0)
  132.         cnt = tcb->rcvcnt;
  133.     /* If there's something on the queue, just return it regardless
  134.      * of the state we're in.
  135.      */
  136.     if(tcb->rcvcnt != 0){
  137.         /* See if the user can take all of it */
  138.         if(tcb->rcvcnt <= cnt){
  139.             cnt = tcb->rcvcnt;
  140.             *bp = tcb->rcvq;
  141.             tcb->rcvq = NULLBUF;
  142.         } else {
  143.             if((*bp = alloc_mbuf(cnt)) == NULLBUF){
  144.                 net_error = NO_SPACE;
  145.                 return -1;
  146.             }
  147.             pullup(&tcb->rcvq,(*bp)->data,cnt);
  148.             (*bp)->cnt = cnt;
  149.         }
  150.         tcb->rcvcnt -= cnt;
  151.         tcb->rcv.wnd += cnt;
  152.         /* Do a window update if it was closed */
  153.         if(cnt == tcb->rcv.wnd){
  154.             tcb->force = 1;
  155.             tcp_output(tcb);
  156.         }
  157.         return cnt;
  158.     } else {
  159.         /* If there's nothing on the queue, our action depends on what state
  160.          * we're in (i.e., whether or not we're expecting any more data).
  161.          * If no more data is expected, then simply return 0; this is
  162.          * interpreted as "end of file".
  163.          */
  164.         switch(tcb->state){
  165.         case LISTEN:
  166.         case SYN_SENT:
  167.         case SYN_RECEIVED:
  168.         case ESTABLISHED:
  169.         case FINWAIT1:
  170.         case FINWAIT2:
  171.             *bp = NULLBUF;
  172.             net_error = WOULDBLK;
  173.             return -1;
  174.         case CLOSED:
  175.         case CLOSE_WAIT:
  176.         case CLOSING:
  177.         case LAST_ACK:
  178.         case TIME_WAIT:
  179.             *bp = NULLBUF;
  180.             return 0;
  181.         }
  182.     }
  183.     return 0;    /* Not reached, but lint doesn't know that */
  184. }
  185. /* This really means "I have no more data to send". It only closes the
  186.  * connection in one direction, and we can continue to receive data
  187.  * indefinitely.
  188.  */
  189. int
  190. close_tcp(tcb)
  191. register struct tcb *tcb;
  192. {
  193.     if(tcb == NULLTCB){
  194.         net_error = INVALID;
  195.         return -1;
  196.     }
  197.     switch(tcb->state){
  198.     case LISTEN:
  199.     case SYN_SENT:
  200.         close_self(tcb,NORMAL);
  201.         return 0;
  202.     case SYN_RECEIVED:
  203.     case ESTABLISHED:
  204.         tcb->sndcnt++;
  205.         tcb->snd.nxt++;
  206.         setstate(tcb,FINWAIT1);
  207.         tcp_output(tcb);
  208.         return 0;
  209.     case CLOSE_WAIT:
  210.         tcb->sndcnt++;
  211.         tcb->snd.nxt++;
  212.         setstate(tcb,LAST_ACK);
  213.         tcp_output(tcb);
  214.         return 0;
  215.     case FINWAIT1:
  216.     case FINWAIT2:
  217.     case CLOSING:
  218.     case LAST_ACK:
  219.     case TIME_WAIT:
  220.         net_error = CON_CLOS;
  221.         return -1;
  222.     }
  223.     return -1;    /* "Can't happen" */
  224. }
  225. /* Delete TCB, free resources. The user is not notified, even if the TCB is
  226.  * not in the CLOSED state. This function should normally be called by the
  227.  * user only in response to a state change upcall to CLOSED state.
  228.  */
  229. int
  230. del_tcp(tcb)
  231. register struct tcb *tcb;
  232. {
  233.     void unlink_tcb();
  234.     struct reseq *rp,*rp1;
  235.  
  236.     if(tcb == NULLTCB){
  237.         net_error = INVALID;
  238.         return -1;
  239.     }
  240.     unlink_tcb(tcb);
  241.     stop_timer(&tcb->timer);
  242.     for(rp = tcb->reseq;rp != NULLRESEQ;rp = rp1){
  243.         rp1 = rp->next;
  244.         free_p(rp->bp);
  245.         free((char *)rp);
  246.     }
  247.     tcb->reseq = NULLRESEQ;
  248.     free_p(tcb->rcvq);
  249.     free_p(tcb->sndq);
  250.     free((char *)tcb);
  251.     return 0;
  252. }
  253. /* Do printf on a tcp connection */
  254. /*VARARGS*/
  255. tprintf(tcb,message,arg1,arg2)
  256. struct tcb *tcb;
  257. char *message,*arg1,*arg2;
  258. {
  259.     struct mbuf *bp;
  260.     int16 len;
  261.     char *cp,*index();
  262.  
  263.     if(tcb == NULLTCB)
  264.         return 0;
  265.  
  266.     len = strlen(message) + 10;    /* fudge factor */
  267.     if((cp = index(message,'%')) != NULLCHAR){
  268.         /* What a gross hack! */
  269.         len += strlen(arg1);
  270.         if((cp = index(cp+1,'%')) != NULLCHAR){
  271.             /* I don't believe I'm writing this */
  272.             len += strlen(arg2);
  273.         }
  274.     }
  275.     bp = alloc_mbuf(len);
  276.     len = sprintf(bp->data,message,arg1,arg2);
  277.     bp->cnt = strlen(bp->data);
  278.     send_tcp(tcb,bp);
  279.     return len;
  280. }
  281.